package com.mj.controller;

import com.alibaba.fastjson.JSON;
import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.util.SignUtils;
import com.mj.common.Constants;
import com.mj.controller.common.QRUtil;
import com.mj.req.BaseResp;
import com.mj.util.ErrCode;
import com.mj.util.IpKit;
import com.mj.util.RedisUtil;
import com.mj.util.StringUtil;
import com.mj.util.XMLUtil;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * 微信支付controller
 * 
 * @author majie
 *
 */
@Controller
@RequestMapping("/wxpay")
public class WxPayController {
	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	@Resource(name = "wxPayService")
	private WxPayService wxService;
	@Resource
	private WxPayConfig payConfig;

	/**
	 * 统一下单 在发起微信支付前，需要调用统一下单接口，获取"预支付交易会话标识"
	 * 
	 * @param request
	 *            请求对象，注意一些参数如appid、mchid等不用设置，方法内会自动从配置对象中获取到（前提是对应配置中已经设置）
	 */

	// 参数还要修改
	@RequestMapping(value = "/unifiedOrder", method = RequestMethod.POST)
	@ResponseBody
	public BaseResp<WxPayUnifiedOrderResult> unifiedOrder(HttpServletRequest request) {
		WxPayUnifiedOrderRequest order = new WxPayUnifiedOrderRequest();
		BaseResp<WxPayUnifiedOrderResult> result = new BaseResp<WxPayUnifiedOrderResult>();
		// 下面参数都需要前端传送过来,这里暂时这么写
		String outTradeNo = StringUtil.get32UUID();
		order.setOutTradeNo(outTradeNo);
		order.setSpbillCreateIp(IpKit.getIpAddr(request));
		order.setTradeType("NATIVE");
		order.setTotalFee(1);
		order.setProductId(StringUtil.get32UUID());
		order.setBody("网费充值");
		WxPayUnifiedOrderResult unifiedOrder;
		try {
			WxPayUnifiedOrderRequest request1 = new WxPayUnifiedOrderRequest();
			BeanUtils.copyProperties(order, request1);
			// 调用微信服务统一下单
			unifiedOrder = this.wxService.unifiedOrder(request1);
			// 将微信订单存入redis
			RedisUtil.set("WxPayOrder:" + outTradeNo, JSON.toJSONString(order));
			result.setDetail(unifiedOrder);
			return result;
		} catch (WxPayException e) {
			logger.error("预支付异常{}", e.getMessage());
			result.setResult(ErrCode.FAILED);
			result.setResultNote("支付异常");
			return result;
		}
	}

	/**
	 * 生成二维码图片并直接以流的形式输出到页面
	 * 
	 * @param code_url
	 * @param response
	 */
	@RequestMapping("qr_code.img")
	@ResponseBody
	public void getQRCode(String code_url, HttpServletResponse response) {
		QRUtil.encodeQrcode(code_url, response);
	}

	/**
	 * 微信通知支付结果的回调地址，notify_url
	 *
	 * @param request
	 * @param response
	 */
	@RequestMapping(value = "payCallBack")
	public void getCallBackData(HttpServletRequest request, HttpServletResponse response) {
		try {
			Map<String, String> kvm = XMLUtil.parseRequestXmlToMap(request);
			// 将map转成支付结果bean
			WxPayOrderNotifyResult orderResult = (WxPayOrderNotifyResult)com.mj.util.BeanUtils.mapToBean(WxPayOrderNotifyResult.class, kvm);
			// 将map转成支付结果bean
			/**
			 * 1.参数校验 2.成功保存充值记录并通知
			 */
			if (SignUtils.checkSign(kvm, this.payConfig.getMchKey())) {
				String out_trade_no = kvm.get("result_code");
				if ("SUCCESS".equals(out_trade_no)) {
					saveOrderAndNotify(out_trade_no, orderResult, Constants.SUCCESS);
					logger.info("out_trade_no: " + kvm.get("out_trade_no") + " pay SUCCESS!");
					response.getWriter().write(
							"<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[ok]]></return_msg></xml>");
				} else {
					saveOrderAndNotify(out_trade_no, orderResult, Constants.FAIL);
					this.logger.error("out_trade_no: " + kvm.get("out_trade_no") + " result_code is FAIL");
					response.getWriter().write(
							"<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[result_code is FAIL]]></return_msg></xml>");
				}
			} else {
				// 签名验证失败的直接不处理
				response.getWriter().write(
						"<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[check signature FAIL]]></return_msg></xml>");
				this.logger.error("out_trade_no: " + kvm.get("out_trade_no") + " check signature FAIL");
			}
		} catch (Exception e) {
			logger.error("接受支付信息异常{}", e.getMessage());
		}
	}

	/**
	 * 保存订单并通知
	 * 这里不该这么玩
	 * @param kvm
	 * @param orderResult
	 */
	private void saveOrderAndNotify(String out_trade_no, WxPayOrderNotifyResult orderResult, String state) {
		// 保存订单并通知
		if (true) {
			// 通知前端页面，移除微信订单
			WebsocketController.broadcast(orderResult.getOutTradeNo(), state);
			RedisUtil.remove("WxPayOrder:" + out_trade_no);
		}
	}

	/**
	 * 调用微信的接口查询订单
	 *
	 * @param transactionId
	 *            微信订单号
	 * @param outTradeNo
	 *            商户系统内部的订单号，当没提供transactionId时需要传这个。 参数二选一
	 */

	@RequestMapping(value = "/queryWxOrder", method = RequestMethod.GET)
	public BaseResp<WxPayOrderQueryResult> queryOrder(@RequestParam(required = false) String transactionId,
			@RequestParam(required = false) String outTradeNo) {
		BaseResp<WxPayOrderQueryResult> result = new BaseResp<>();
		try {
			WxPayOrderQueryResult orderResult = this.wxService.queryOrder(transactionId, outTradeNo);
			if (orderResult == null) {
				result.setResult(ErrCode.FAILED);
				result.setResultNote("订单不存在");
				return result;
			} else {
				result.setDetail(orderResult);
				result.setResult(ErrCode.SUCCESS);
				return result;
			}
		} catch (WxPayException e) {
			result.setResult(ErrCode.FAILED);
			result.setResultNote("服务器异常");
			return result;
		}
	}

}
